home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9207.ZIP
/
AVKCAPT.ZIP
/
COPYLIST.C
< prev
next >
Wrap
Text File
|
1992-03-18
|
24KB
|
713 lines
//-------------------------------------------------------------------------
// ActionMedia II Programmer's Toolkit
//
// Windows Sample Code Shared Functions
//
// Module Name: copylist.c
//
// Description: Create a copy list for a given connector destination box.
//
// Copyright Intel Corp. 1991, 1992
// All Rights Reserved.
//
//-------------------------------------------------------------------------
//
// Exported functions from this module:
//
// UpdateCopyList
//
//-------------------------------------------------------------------------
// NOTES ON CopyList
//
// The function UpdateCopyList is called by a Windows timer at set
// intervals. It runs through the portion of the Window Manager's list
// windows that are 'above' the target AVK window on the desktop. It
// checks each active window found for overlap with the target window.
// If the active window overlaps, it extracts the intersecting rectangle
// and adds it to a clip list. If the clip list has changed or the target
// rectangle has changed since the last timer tick, it calls Clip2Copy()
// to produce a copylist and then passes the copylist to the AVK
// connector.
//
// The function Clip2Copy() converts a clip list to a copy list. A clip
// is an array of rectangles which are to be EXCLUDED from the AVK display
// in a given area of a view. AVK's call AvkConnCopyList() passes its
// connector an array of rectangles defining the areas to be INCLUDED in
// the AVK display. The diagram shows a large box where a AVK image is
// being displayed, overlaid by a smaller dialog box. To prevent the AVK
// image from showing through the black lettering in the dialog box
// (speckling), we must create a copy list of the areas not encompassed by
// the dialog box. The code below takes the BOX structures defining the
// AVK window and the overlapping dialog box window (and any other
// overlapping windows) and produces an array of boxes to be included in
// the copy list (shown by the dotted lines and named Include box 1-4).
// This is creation of a copy list in its simplest form.
//
// AVK Window A
// +--------------------------------------------------+
// | |
// | |
// | |
// | |
// | Include box 1 |
// | |
// | |
// |..........+-----------------------+...............|
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | Include | Overlapping window B | Include box 3 |
// | box 2 | | |
// | | | |
// | | Region to be excluded | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// |..........+-----------------------+...............|
// | |
// | |
// | Include box 4 |
// | |
// | |
// | |
// +--------------------------------------------------+
//
//
//
// In the case where there is only one overlapping box, building the copy
// list is quite straightforward. The four copy boxes would have the
// x/y coordinates as follows:
//
// box 1 = A.x1/A.y1 A.x2/B.y1
// box 2 = A.x1/B.y1 B.x1/B.y2
// box 3 = A.x1/B.y2 A.x2/A.y2
// box 4 = B.x1/B.y1 A.x2/B.y2
//
// When there are 2 or more overlapping boxes, it is more complicated
// as the included areas must be subdivided into smaller rectangles
// based on the number, sizes and positions of the overlapping boxes.
//
// The code below creates an array of the x coordinates of all boxes
// (including the AVK window) and an array of all y coordinates. It
// then sorts the two arrays into ascending order. It can then extract
// from these arrays a matrix of boxes describing the entire AVK window
// where each box is either an INCLUDING or EXCLUDING region. It then
// goes through the matrix and determines if each box is in fact one of
// the overlapping boxes passed in by the user. If not, the box is an
// INCLUDING region and is added to the copy list. When done, the copy
// list is ready to pass to AvkConnCopyList().
//
// Note that in the case diagrammed above, this algorithm would produce a
// copy list of 8 smaller boxes instead of the four pictured above and
// would look like this:
//
// AVK Window A
// +--------------------------------------------------+
// | . . |
// | Include . Include box 2 . Include box 3 |
// | box 1 . . |
// | . . |
// | . . |
// | . . |
// | . . |
// |..........+-----------------------+...............|
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | Include | Overlapping window B | Include box 5 |
// | box 4 | | |
// | | | |
// | | Region to be excluded | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// |..........+-----------------------+...............|
// | . . |
// | . . |
// | Include . Include box 7 . Include box 8 |
// | box 6 . . |
// | . . |
// | . . |
// +--------------------------------------------------+
//
// This method produces more boxes than is necessary to describe the
// INCLUDE space. We can minimize this problem by combining adjacent
// INCLUDE rectangles as we scan the matrix and make up the copy list.
// We don't try to do a best fit analysis coalescing the rectangles
// since it would add both code complexity and processing time. We just
// combine rectangles that are horizontally adjacent since we are processing
// them in horizontal order. This will result in either the minimum
// necessary rectangles or close enough to the minimum. In the case of
// two clip windows overlapping each other, 18 rectangles are created and
// then coalesced into 8. The best case here would have been 6.
//
// NOTA BENE: This function assumes that the boxes in the caller's clip
// list are all truncated to the borders of the AVK window for whom we
// are preparing the copy list. Callers can truncate by hand or use the
// Windows function IntersectRect() to do the work for them. Note the use
// of a cast with the Windows function SetRect() below to make it operate
// on a BOX structure as an example. Truncation can be added easily, if
// desired, by simply using the coordinates in the pWin rectangle as
// bounding coordinates and truncating any clip box coordinates that
// fall outside this range (perhaps in the AddBoxCoords() function).
//
//-------------------------------------------------------------------------
#include <windows.h>
#include <stdlib.h>
#include "avkapi.h"
#define COPYLIST_NOEXTERNS 1
#include "copylist.h"
static BOX CopyList[NUM_COPY_BOXES];
static WORD CopyCnt;
#define NUM_COORDS (NUM_CLIP_RECTS << 1)
static int xCoords[NUM_COORDS];
static int yCoords[NUM_COORDS];
static WORD xCnt;
static WORD yCnt;
static WORD cxScreen = 0;
static WORD cyScreen = 0;
static double xDelta;
static double yDelta;
static BOOL Clip2Copy(BOX *, BOX *, WORD);
static BOOL InClipList(int, int, BOX *, WORD);
static void BuildCoordArrays(BOX *, BOX *, WORD);
static void AddBoxCoords(BOX *);
static int fnCmpWords(const int *, const int *);
static void Win2AvkCoords(RECT *, BOX *);
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL UpdateCopyList(pCopyList, prectTarget, cxView, cyView, BOOL *pbUpdated)
//
//PARMS IN:
//
// COPYLIST *pCopyList pointer to COPYLIST structure that identifies
// a rectangle being used as an AVK connector
// destination.
//
// RECT *prectTarget pointer to a RECT structure describing the
// dimensions of the destination box (in AVK
// coordinates) of the connector to be clipped.
//
// WORD cxView x resolution of the AVK view plane - needed
// to scale Windows RECT coordinates to AVK
// BOX coordinates
//
// WORD cyView y resolution of the AVK view plane - needed
// to scale Windows RECT coordinates to AVK
// BOX coordinates
//
//PARMS OUT:
//
// BOOL *pbUpdated TRUE if copylist updated. FALSE if no changes.
//
//DESCRIPTION:
//
// Make a list of the intersecting rectangles that occlude our AVK
// destination box and create a copylist to be passed to the AVK
// box's connector. This process is driven by a Windows timer.
//
//RETURN:
// 0 if successful
// 0xffff if Clip2Copy error
// Anything else is an AVK error.
//
//-------------------------------------------------------------------------
I16
UpdateCopyList(COPYLIST *pCopyList, RECT *prectTarget, WORD cxView, WORD cyView,
BOOL *pbUpdated)
{
BOOL bUpdateCopyList; // TRUE if new copylist was created
WORD ClipCnt = 0; // number of clip boxes made
I16 rc; // return code
HWND hwndCurr; // handle of current window being checked
RECT rectCurr; // dimensions of hwndCurr
RECT rectIntersect; // intersection of a window and the
// AVK destination rectangle
rc = AVK_ERR_OK;
// If this view has no video connector (for example, in the case of
// an audio-only file), no clipping needed.
if (pCopyList->hConn == (HAVK)0)
return rc;
CopyCnt = 0;
*pbUpdated = FALSE;
// Set up for RECT to BOX conversion.
// Get the screen coordinates the first time in.
if (!cxScreen)
{
cxScreen = GetSystemMetrics(SM_CXSCREEN);
cyScreen = GetSystemMetrics(SM_CYSCREEN);
}
// Compute the delta values to convert from screen to view coordinates.
xDelta = ((double)cxView / (double)cxScreen);
yDelta = ((double)cyView / (double)cyScreen);
// Start enumerating windows from our display window.
hwndCurr = pCopyList->hwndTarget;
// Init update flag - will be TRUE if there is any change in the
// clip list from last time this was done.
bUpdateCopyList = FALSE;
// Now walk through the windows that are 'above' our display window
// and find any that overlap. For each overlapping window, get
// the actual intersection and add it to the clip list. Note that
// we compare each intersecting rectangle with the one already in
// the clip list at the current position. If they are different,
// or we don't have any current entry in that slot, we set the
// flag to indicate that the clip list has changed. Only if the copylist
// has changed do we create a new copy list. Otherwise, there is
// no need to update the copylist at this time.
while (hwndCurr = GetNextWindow(hwndCurr, GW_HWNDPREV))
{
// Only worry about it if it is visible.
if (IsWindowVisible(hwndCurr))
{
// Get its dimensions and convert to AVK coords.
GetWindowRect(hwndCurr, &rectCurr);
Win2AvkCoords(&rectCurr, (BOX *)&rectCurr);
// Only worry about it if it intersects. Extract
// the intersecting rectangle.
if (IntersectRect(&rectIntersect, &rectCurr, prectTarget))
{
// If we had a previous rect in the copy list and
// it was the same size, don't bother to copy it.
// If it was a different size, copy it and set the
// flag to tell us that the list has changed.
if (ClipCnt < pCopyList->ClipCnt)
{
if (!EqualRect(&pCopyList->rectClipList[ClipCnt],
&rectIntersect))
{
bUpdateCopyList = TRUE;
CopyRect(&pCopyList->rectClipList[ClipCnt],
&rectIntersect);
}
}
else
{
// This rect has no counterpart in the old copy
// list since we are past the end of the old list
// , so we KNOW that the list has changed. Copy it
// in and set the changed flag.
bUpdateCopyList = TRUE;
CopyRect(&pCopyList->rectClipList[ClipCnt],
&rectIntersect);
}
// If we run out of elements in the list, then
// just stop finding more rects. We will only
// use the ones found.
if (++ClipCnt >= NUM_CLIP_RECTS)
hwndCurr = NULL;
}
}
}
// If we finish with a different number than last time, we know the
// list is changed. Flag it. We need this check since a new list
// in which each box is identical to its counterpart in the old
// list, but where there are fewer boxes in the new list will not
// have been flagged above.
if (ClipCnt != pCopyList->ClipCnt)
bUpdateCopyList = TRUE;
// Check whether the destination box has changed since the last
// time. A change will trigger a copylist update even if the
// copylist itself has not changed. Update the stored target
// rectangle with the new values.
if (!EqualRect(&pCopyList->rectTarget, prectTarget))
{
CopyRect(&pCopyList->rectTarget, prectTarget);
bUpdateCopyList = TRUE;
}
// Update the number of clip rects now in the rectClipList array.
pCopyList->ClipCnt = ClipCnt;
// At this point, we have build a new clip list of intersecting
// rectangles. If the list has changed in any way from the
// last one, then we convert the copylist to a copylist.
if (bUpdateCopyList)
{
// Nothing in the copylist as yet.
CopyCnt = 0;
// If we have any overlapping rectangles in the clip list,
// create a copylist from the copylist.
if (ClipCnt)
{
if (!Clip2Copy((BOX *)prectTarget, (BOX *)pCopyList->rectClipList,
ClipCnt))
return COPY_ERROR;
}
else
{
// If no clip rectangles were found, create a copy list of one
// element, the entire target rectangle. This will remove the
// old copy list and make the whole view region visible.
CopyCnt = 1;
CopyRect((RECT *)CopyList, prectTarget);
}
// Now call AVK and pass the copy list down to microcode.
if ((rc = AvkConnCopyList(pCopyList->hConn, CopyCnt, CopyList,
AVK_TIME_IMMEDIATE)) == AVK_ERR_OK)
*pbUpdated = TRUE;
}
return rc;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// Clip2Copy(pWin, pClip, nClip)
//
//PARMS IN:
//
// BOX *pWin; address of the destination box of the connector that
// you are preparing this copy list for.
// BOX *pClip; address of an array of box pointers containing the
// overlapping boxes
// WORD nClip; number of boxes in the pClip array.
// Must be <= NUM_CLIP_RECTS
//
//DESCRIPTION:
//
// Takes an array of boxes overlapping the AVK window in the view
// representing the areas to be EXCLUDED from the AVK display and
// builds an array of boxes representing the areas to be INCLUDED
// in the AVK display (all areas NOT covered by the overlapping boxes).
//
//RETURN:
//
// TRUE if successful.
// FALSE if caller specified too many clip boxes or if it would result
// in too many copy boxes (CopyCnt > NUM_COPY_BOXES).
//
//-------------------------------------------------------------------------
BOOL
Clip2Copy(BOX *pWin, BOX *pClip, WORD nClip)
{
int nCopy;
WORD x, y;
BOOL bLastBoxIncluded;
if (nClip > NUM_CLIP_RECTS)
return FALSE;
// First, build the sorted arrays of x and y coordinates.
BuildCoordArrays(pWin, pClip, nClip);
nCopy = -1; // start below 0 - will be incremented before
// being used!
for (y = 0; y < (yCnt - 1); y++)
{
// If we have two boxes sharing the same y coordinate, we have
// a duplicate y coordinate in the array and would produce
// an extra erroneous 1-line high include box. Just skip it.
if (yCoords[y] == yCoords[y + 1])
continue;
// We are starting a new horizontal level, so make sure we
// indicate that we shouldn't try to coalesce this box with
// the prior one.
bLastBoxIncluded = FALSE;
for (x = 0; x < (xCnt - 1); x++)
{
// Duplicate x coords should be skipped as well.
if (xCoords[x] == xCoords[x + 1])
continue;
// If the box is not in the clip list, we will include
// it in the copy list.
if (!InClipList(xCoords[x], yCoords[y], pClip, nClip))
{
// Combine horizontally adjacent rectangles.
// If the last rectangle we processed on this level
// was included in the copy list, just stretch its
// x2 coordinate to cover this one too. If the
// prior box was not put into the copy list, we have
// to make a new entry for this box.
if (bLastBoxIncluded)
CopyList[nCopy].x2 = xCoords[x + 1];
else
{
// Exit with an error if we are about to overrun
// the copy list maximum.
if (++nCopy >= NUM_COPY_BOXES)
return FALSE;
// We are entering a new rectangle in the copy
// list. Increment the subscript for it.
SetRect((RECT *)&CopyList[nCopy],
xCoords[x], yCoords[y],
xCoords[x+1], yCoords[y+1]);
// Turn on the flag to indicate that adjacent
// rectangles should be coalesced with this one
// instead of being added as separate rectangles.
bLastBoxIncluded = TRUE;
}
}
else
// This rectangle is not being added. Force next
// acceptable rectangle to be added as a new rectangle
// instead of being combined.
bLastBoxIncluded = FALSE;
}
}
// We have been using nCopy as the subscript. Increment by one
// to make the actual number of elements added.
CopyCnt = (WORD)nCopy + 1;
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// BuildCoordArrays(pWin, pClip, nClip)
//
//PARMS IN:
//
// BOX *pWin; address of the destination box of the connector that
// you are preparing this copy list for.
// BOX *pClip; address of an array of box pointers containing the
// overlapping boxes
// WORD nClip; number of boxes in the pClip array.
// Must be <= NUM_CLIP_RECTS
//
//DESCRIPTION:
//
// Builds two coordinate arrays. xCoord[] holds all of the x1 and x2
// values from the display window and all clip boxes. yCoord[] holds
// all of the y coordinates. Both coordinate arrays are then sorted
// into ascending order. We can now use them to break the connector
// destination box down into a matrix of INCLUDED and EXCLUDED boxes
// as in the second diagram above.
//
//RETURN:
//
// None
//
//-------------------------------------------------------------------------
static void
BuildCoordArrays(BOX *pWin, BOX *pClip, WORD nClip)
{
WORD i;
// Zero out the x and y coord counters. These are the subscripts
// into the xCoord[] and yCoord[] arrays and are incremented in
// AddBoxCoords().
xCnt = yCnt = 0;
// Start by adding the x/y coordinates of the AVK window to the
// xCoord[] and yCoord[] arrays. These are necessary as the
// bounding coordinates.
AddBoxCoords(pWin);
// Now add the coordinates of all of the clip boxes.
for (i = 0; i < nClip; i++)
AddBoxCoords(&pClip[i]);
// Sort the xCoord[] and yCoord[] arrays into ascending order.
qsort(xCoords, xCnt, sizeof(int), fnCmpWords);
qsort(yCoords, xCnt, sizeof(int), fnCmpWords);
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// AddBoxCoords(pBox)
//
//PARMS IN:
//
// BOX *pBox; pointer to a box whose coordinates are to be added
// to the xCoords[] and yCoords[] arrays.
//
//DESCRIPTION:
//
// Adds the x1 and x2 coords into the xCoords[] array and the y1 and
// y2 coords into the yCoords[] array.
//
// xCnt and yCnt are incremented for each coordinate added.
//
//RETURN:
//
// None
//
//-------------------------------------------------------------------------
static void
AddBoxCoords(BOX *pBox)
{
// Add the box's x coordinates to the xCoord[] array.
xCoords[xCnt++] = pBox->x1;
xCoords[xCnt++] = pBox->x2;
// Add the box's y coordinates to the yCoord[] array.
yCoords[yCnt++] = pBox->y1;
yCoords[yCnt++] = pBox->y2;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// InClipList(x, y, pClip, nClip)
//
//PARMS IN:
//
// int x; x coordinate of point to be tested
// int y; y coordinate of point to be tested
// BOX *pClip; address of the array of pointers to clip list boxes
// WORD nClip; number of boxes in the pClip array.
//
//DESCRIPTION:
//
// Builds a POINT structure from the x,y coordinates and tests whether
// this point is in any of the boxes in the clip list array.
//
//RETURN:
//
// TRUE if the point is within (or on the top or left edge) of any of
// the boxes in the clip list.
// FALSE if not.
//
//-------------------------------------------------------------------------
static BOOL
InClipList(int x, int y, BOX *pClip, WORD nClip)
{
WORD i;
POINT Point;
Point.x = x;
Point.y = y;
for (i = nClip; i; i--, pClip++)
{
if (PtInRect((LPRECT)pClip, Point))
return TRUE;
}
return FALSE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// fnCmpWords(pElm1, pElm2)
//
//PARMS IN:
//
// WORD *pElm1; pointer to first element to be compared
// WORD *pElm2; pointer to second element to be compared
//
//DESCRIPTION:
//
// Function to compare two WORDs for qsort().
//
//RETURN:
//
// <0 if first value less than second.
// 0 if both values equal
// >0 if first value greater than second.
//
//-------------------------------------------------------------------------
static int
fnCmpWords(const int *pElm1, const int *pElm2)
{
return *pElm1 - *pElm2;
}
static VOID
Win2AvkCoords(RECT *pRect, BOX *pBox)
{
pBox->x1 = (I16)((double)pRect->left * xDelta);
pBox->y1 = (I16)((double)pRect->top * yDelta);
pBox->x2 = (I16)((double)pRect->right * xDelta);
pBox->y2 = (I16)((double)pRect->bottom * yDelta);
}